package com.neuronbit.businessflow.intellij.model;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * The type Call.
 */
@Getter
@ToString(callSuper = true)
public class Call extends Node {
    @Setter
    private Type type;
    @Setter
    private FormattedMethodString method;
    private final Map<String, Param> params = new TreeMap<>();
    private final Set<Return> returns = new HashSet<>(0);

    /**
     * Instantiates a new Call.
     */
    public Call() {
        super(null, null, NodeType.CALL);
    }

    /**
     * Instantiates a new Call.
     *
     * @param id       the id
     * @param name     the name
     * @param nodeType the node type
     */
    public Call(String id, String name, NodeType nodeType) {
        super(id, name, nodeType);
    }

    /**
     * Gets param value.
     *
     * @param index the index
     * @return the param value
     */
    public String getParamValue(String index) {
        Param param = params.get(index);
        if (param != null && param.getValue() != null) {
            return param.getValue().toString();
        }
        return "";
    }

    /**
     * Sets param.
     *
     * @param index the index
     * @param value the value
     */
    public void setParam(String index, String value) {
        Param param = params.get(index);
        if (param != null) {
            param.setValue(value);
        } else {
            params.put(index, new Param(index, value));
        }
    }

    /**
     * Gets return value.
     *
     * @param name the name
     * @return the return value
     */
    public String getReturnValue(String name) {
        Optional<Return> first = returns.stream().filter(r -> name.equals(r.getName())).findFirst();
        if (first.isPresent()) {
            return Objects.requireNonNull(first.get().getValue()).toString();
        } else {
            return "";
        }
    }

    /**
     * Sets return.
     *
     * @param name  the name
     * @param value the value
     */
    public void setReturn(String name, String value) {
        Iterator<Return> iterator = returns.iterator();
        boolean found = false;
        while (iterator.hasNext()) {
            Return aReturn = iterator.next();
            if (name.equals(aReturn.getName())) {
                found = true;
                if (StringUtils.isBlank(value)) {
                    iterator.remove();
                } else {
                    aReturn.setValue(value);
                }
            } else {
                //clean the empty return
                if (StringUtils.isBlank(aReturn.getValue())) {
                    iterator.remove();
                }
            }
        }
        if (!found && StringUtils.isNotBlank(value)) {
            returns.add(new Return(name, value));
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;
        Call call = (Call) o;
        return Objects.equals(type, call.type) && Objects.equals(method, call.method) && Objects.equals(params, call.params) && Objects.equals(returns, call.returns);
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), type, method, params, returns);
    }
}
